Add manual trigger mode for bundle refresh - #112
Conversation
|
@MohamedFazil1406 thank you for working on this! can you sign your commits please for the DCO check to pass? |
ee67282 to
d413338
Compare
|
Thanks for the heads-up! I've signed off all the commits and force-pushed the updated branch. The DCO check should pass now. |
Signed-off-by: MohamedFazil1406 <mohamedfazil01406@gmail.com>
Signed-off-by: MohamedFazil1406 <mohamedfazil01406@gmail.com>
Signed-off-by: MohamedFazil1406 <mohamedfazil01406@gmail.com>
d413338 to
ecfd524
Compare
|
@MohamedFazil1406 looks like there are some real compilation failures, mind taking a look? |
|
ok i will check |
Signed-off-by: MohamedFazil1406 <mohamedfazil01406@gmail.com>
5208b45 to
1a6e0d2
Compare
|
Hi! I've updated the PR and fixed the issues. Could you please review it when you have time? Thank you! |
sspaink
left a comment
There was a problem hiding this comment.
Thanks for working on this! Unfortunately the PR isn't mergeable as-is: the manual-trigger feature isn't wired up, the new tests call methods that were never added (so the module won't compile), the validation the summary describes is missing, and the diff also reverts the max_size_bytes feature that's on main. Details inline. Verified against the PR head and main. Recommend rebasing on current main (to drop the max_size_bytes deletion) and adding the actual wiring — BundleConfig.trigger + accessors, Bundle.getTrigger, propagation in initialize, and the validation — before the tests can compile and pass.
Minor: the new Trigger enum and added blocks use 4-space indentation (surrounding code is 2-space), and startPolling gains stray double blank lines.
| new Config.BundleConfig() | ||
| .setService("test-service") | ||
| .setResource("/bundles/test.tar.gz") | ||
| .setTrigger(Config.Trigger.MANUAL) |
There was a problem hiding this comment.
This won't compile — Config.BundleConfig.setTrigger(...) doesn't exist. The diff adds the Config.Trigger enum but no trigger field, setTrigger, or getTrigger on BundleConfig (grep trigger in Config.java finds only the enum). Same problem at line 100 with plugin.getBundle(...).getTrigger() — BundleDownloader/Bundle has setTrigger but no getTrigger. Both test methods fail to compile, so the whole opa-services test source set won't build.
| servicePlugin == null ? null : servicePlugin.getService(bundleConfig.getService()); | ||
|
|
||
| Bundle bundle = | ||
| plugin.bundles.put( |
There was a problem hiding this comment.
The configured trigger is never propagated, so MANUAL has no effect. This builder chain sets service/resource/polling but never calls .setTrigger(bundleConfig.getTrigger()), so the downloader keeps its default PERIODIC and the new MANUAL branch in startPolling is unreachable via config. (It also can't, yet — BundleConfig.getTrigger() doesn't exist.) Even once it compiles, initialize_manualTrigger_setsTrigger would fail because the bundle stays PERIODIC.
|
|
||
| assertTrue( | ||
| errors.stream() | ||
| .anyMatch(e -> e.contains("cannot specify polling when trigger is manual"))); |
There was a problem hiding this comment.
The validation this asserts doesn't exist. BundlePlugin.validate() has no check that rejects polling when the trigger is manual (no trigger reference in the method), so no error containing "cannot specify polling when trigger is manual" is ever produced and this assertion fails. The "reject polling configuration when using the manual trigger" change from the PR summary is missing from the diff.
| */ | ||
| @JsonProperty("max_size_bytes") | ||
| private long maxSizeBytes = DEFAULT_MAX_SIZE_BYTES; | ||
| public static final long DEFAULT_MAX_SIZE_BYTES = 1024L * 1024L * 1024L; |
There was a problem hiding this comment.
This reverts the max_size_bytes feature that's on main — likely a stale-branch/bad-merge artifact. The diff deletes BundleConfig.maxSizeBytes (the field, getMaxSizeBytes/setMaxSizeBytes public API, and its Javadoc), drops the bundle.setMaxSizeBytes(...) wiring in BundlePlugin, and switches to the 2-arg new TarballBundleLoader(name, bundleData) (BundlePlugin.java:186). On main this is a configurable DoS safeguard (512 MB default, capping both the compressed download and decompressed contents). Net effect: the configurable limit is gone (falls back to the loader's built-in default) and this line silently changes the default 512 MB → 1 GB. This is unrelated to the trigger feature and shouldn't land; please rebase on current main.
| return initialActivation; | ||
| } | ||
|
|
||
| public CompletableFuture<Void> refresh() { |
There was a problem hiding this comment.
refresh() is broken for repeated use and blocks the caller. It calls downloadBundle() synchronously on the caller's thread (every other download runs on the scheduler, doing blocking network I/O), and returns initialActivation — a one-shot CompletableFuture whose completion sites are all guarded by if (!initialActivation.isDone()). So the returned future reflects only the first activation: after the first success it's already completed, and later refresh() calls return an already-done future that doesn't track that refresh's outcome (success or failure). Also, in MANUAL mode startPolling returns initialActivation without ever scheduling a download, so getInitialActivation() never completes until a refresh() occurs — which can hang plugin startup if lifecycle code awaits it. Consider returning a fresh future per refresh and dispatching the download on the scheduler.
There was a problem hiding this comment.
Thanks for the review! I've addressed the compile issues, trigger propagation, validation, and rebased onto the latest main. For the refresh() redesign, I understand the goal of returning a fresh future per refresh while keeping initialActivation for the first activation only. Before I refactor it, could you clarify the expected behavior for manual mode? Should startPolling() return an already-completed initialActivation in manual mode, or should initialActivation only complete after the first successful refresh()?
There was a problem hiding this comment.
I checked how OPA's Go bundle plugin handles this:
- Manual mode does no download at startup — the downloader's
Start()is a no-op unless the trigger is periodic; a fetch only happens onTrigger(). - Readiness = a bundle actually activated — the plugin stays
NotReadyuntil every bundle has activated once. But OPA'sStart()never blocks on this; readiness is just reported status.
So no, startPolling() shouldn't return a pre-completed initialActivation. Keep it meaningful (first successful activation). The reason a never-completing future hangs us is SDK-specific: build() blocks up to 60s for bundles to reach OK, and BundlePlugin.start() couples that status to allOf(initialActivation). The fix is to decouple them, like OPA:
start()shouldn't gate the plugin'sOKon a manual bundle'sinitialActivation— loaders are started and awaiting triggers, so the plugin reachesOKandbuild()won't hang.initialActivationcompletes only on the first successful refresh — don't complete it eagerly.refresh()returns a fresh future per call, dispatched on the scheduler (not synchronously on the caller's thread).
A caller wanting to block until the first manual bundle loads awaits refresh(), not getInitialActivation().
Signed-off-by: MohamedFazil1406 <mohamedfazil01406@gmail.com>
Signed-off-by: MohamedFazil1406 <mohamedfazil01406@gmail.com>
Signed-off-by: MohamedFazil1406 <mohamedfazil01406@gmail.com>
Signed-off-by: MohamedFazil1406 <mohamedfazil01406@gmail.com>
Signed-off-by: MohamedFazil1406 <mohamedfazil01406@gmail.com>
Signed-off-by: MohamedFazil1406 <mohamedfazil01406@gmail.com>
…hamedFazil1406/java-opa-sdk into feature/manual-bundle-trigger
Summary
This PR adds support for a manual trigger mode for bundle refresh while preserving the existing periodic polling behavior as the default.
##Issues #65
Changes
Triggerconfiguration withPERIODIC(default) andMANUALmodes.BundleConfigto support the newtriggeroption.BundlePlugintoBundleDownloader.BundleDownloaderto skip automatic polling when the trigger isMANUAL.refresh()method to allow bundles to be refreshed on demand.Testing
./gradlew :opa-services:compileJavaopenssl, which is not available in my Windows environment, resulting in an unrelated test initialization failure.